// Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
//
// Licensed under the Mulan PSL v2.
// You can use this file according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the License at
//
//     http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
// FOR MORE DETAILS.

/*
 * @Author: wanghuan wanghuan@sgsimulation.com
 * @Date: 2024-09-05 11:13:47
 * @LastEditors: qiulin 1746365080@qq.com
 * @LastEditTime: 2024-12-23 15:33:52
 * @FilePath: \SGFEM\Import\BDFImport\test\BDFFile\BDFParserTest.cpp
 */

#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

#include "gtest/gtest.h"

#include "Utility/FileSystem/SGFileSystem.h"

#include "DBManager/DBServiceFactory.h"

#include "Import/BDFImport/BDFImport.h"
// using SG::DataStructure::Common::Status;
// using SG::DataStructure::Common::TOLERANCE;
using namespace SG::DBManager;
using namespace SG::Import;
using namespace SG::DataStructure;

extern std::shared_ptr<DBServiceFactory> DB_SERVICEFACTORY;
extern std::vector<std::string>          dividedEntryInfo;

class NastranParseBDFTest : public ::testing::Test
{
  public:
    static void SetUpTestSuite ()
    {
        DB_SERVICEFACTORY->ClearDatabase ();
    }
};

// 处理文件的函数
void processFile (const std::string& filename, const std::vector<std::string>& patterns)
{
    // 打开文件进行读取
    std::ifstream infile (filename);
    if (!infile.is_open ())
    {
        std::cerr << "无法打开文件: " << filename << "\n";
        return;
    }

    // 创建一个临时的存储空间来存储保留的行
    std::vector<std::string> remainingLines;
    std::string              line;

    // 读取文件中的每一行
    while (std::getline (infile, line))
    {
        bool shouldRemove = false;

        bool const isEmpty = std::all_of (line.begin (), line.end (), [] (char c) { return c == ' '; });
        if (isEmpty)
        {
            shouldRemove = true;
        }
        // 遍历 vector 中的每个模式，检查该行是否匹配
        for (const auto& pattern : patterns)
        {
            if (line.find (pattern) == 0)
            {  // 如果行以 pattern 开头
                shouldRemove = true;
                break;
            }
        }

        // 如果该行不需要删除，则保留该行
        if (!shouldRemove)
        {
            remainingLines.push_back (line);
        }
    }

    infile.close ();  // 关闭输入文件

    // 将保留的行写回文件
    std::ofstream outfile (filename, std::ios::trunc);  // 以截断模式打开文件，清空并重新写入
    if (!outfile.is_open ())
    {
        std::cerr << "无法打开文件进行写入: " << filename << "\n";
        return;
    }

    for (const auto& remainingLine : remainingLines)
    {
        outfile << remainingLine << "\n";
    }

    outfile.close ();  // 关闭输出文件
}
#include <DataStructure/Input/Solver/Subcase.h>

#include "DBManager/IService/Input/Subcase/ISubcaseService.h"
TEST_F (NastranParseBDFTest, ParseFileSLOAD)
{
    auto _imp     = std::make_shared<BDFImporter> (DB_SERVICEFACTORY);
    auto filePath = SG::Utility::FileSystem::getTestDataPath ("Import/BDF/SLOAD_Import.bdf");
    _imp->Load (filePath.c_str ());

    auto                            par        = DB_SERVICEFACTORY->get<ISubcaseService> ()->GetSubcase ();
    auto                            subcasepar = par.GetValue ("1");
    SG::DataStructure::FEM::Subcase sub (subcasepar);

    ASSERT_EQ (sub.GetLoadId (), 1000000);
}

TEST_F (NastranParseBDFTest, ParseFileNormalModesAnalysis)
{
    auto _imp     = std::make_shared<BDFImporter> (DB_SERVICEFACTORY);
    auto filePath = SG::Utility::FileSystem::getTestDataPath ("Import/BDF/casestudy_apply_spectra_abs.bdf");
    _imp->Load (filePath.c_str ());
}

#include "DBManager/IService/Input/Property/IPCOMPGService.h"
using SG::DataStructure::Common::TOLERANCE;
TEST_F (NastranParseBDFTest, ParseFilePCOMPG)
{
    auto _imp     = std::make_shared<BDFImporter> (DB_SERVICEFACTORY);
    auto filePath = SG::Utility::FileSystem::getTestDataPath ("Import/BDF/actual_mat8_pcompg_cquad4.bdf");
    _imp->Load (filePath.c_str ());

    SG::DataStructure::FEM::PCOMPGData data;
    ASSERT_EQ (DB_SERVICEFACTORY->get<IPCOMPGService> ()->FindById (1, data), SG::DataStructure::Common::Status::STATUS_Success);

    ASSERT_EQ (data.m_id, 1);
    ASSERT_NEAR (data.m_SB, 37.0, TOLERANCE);  // 37.0为SB
    ASSERT_EQ (data.m_FT, 4);                  // STRN对应4
    ASSERT_EQ (data.m_PLYList.size (), 25);

    // 检查首层和末层
    ASSERT_EQ (data.m_PLYList.front ().m_GPLYID, 1001);
    ASSERT_EQ (data.m_PLYList.back ().m_GPLYID, 1025);

    // 检查所有层的MID和THICK
    for (const auto& ply : data.m_PLYList)
    {
        ASSERT_EQ (ply.m_MID, 1);
        ASSERT_NEAR (ply.m_THICK, 0.216, TOLERANCE);
        ASSERT_EQ (ply.m_SOUT, 1);
    }

    // 检查部分层的角度
    ASSERT_NEAR (data.m_PLYList[0].m_THETA, 45.0, TOLERANCE);
    ASSERT_NEAR (data.m_PLYList[1].m_THETA, 0.0, TOLERANCE);
    ASSERT_NEAR (data.m_PLYList[2].m_THETA, 45.0, TOLERANCE);
    ASSERT_NEAR (data.m_PLYList[3].m_THETA, 0.0, TOLERANCE);
    ASSERT_NEAR (data.m_PLYList[24].m_THETA, 0.0, TOLERANCE);
}

#include "DBManager/IService/Input/Constraint/IRBE2Service.h"
TEST_F (NastranParseBDFTest, RBE2Bug)
{
    auto _imp     = std::make_shared<BDFImporter> (DB_SERVICEFACTORY);
    auto filePath = SG::Utility::FileSystem::getTestDataPath ("Import/BDF/actual_mat8_pcompg_cquad4_T1.bdf");
    _imp->Load (filePath.c_str ());

    SG::DataStructure::FEM::RBE2Data data;
    ASSERT_EQ (DB_SERVICEFACTORY->get<IRBE2Service> ()->FindById (1263, data), SG::DataStructure::Common::Status::STATUS_Success);

    // RBE2        1263    1325  123456      55      56      57      58      59+
    //+       0.0
    ASSERT_EQ (data.m_id, 1263);
    ASSERT_EQ (data.m_masterNode, 1325);
    ASSERT_EQ (data.m_slaveDOFs, 123456);
    ASSERT_EQ (data.m_alpha, 0);
    ASSERT_EQ (data.m_slaveNodes.size (), 5);  // 确保从节点数量正确
    ASSERT_EQ (data.m_slaveNodes[0], 55);
    ASSERT_EQ (data.m_slaveNodes[1], 56);
    ASSERT_EQ (data.m_slaveNodes[2], 57);
    ASSERT_EQ (data.m_slaveNodes[3], 58);
    ASSERT_EQ (data.m_slaveNodes[4], 59);
}

#include "DBManager/IService/Input/Parameter/ISETSService.h"
TEST_F (NastranParseBDFTest, SETTest)
{
    auto _imp     = std::make_shared<BDFImporter> (DB_SERVICEFACTORY);
    auto filePath = SG::Utility::FileSystem::getTestDataPath ("Import/BDF/SETTest.bdf");
    _imp->Load (filePath.c_str ());

    SG::DataStructure::FEM::SETSData setData;
    ASSERT_EQ (DB_SERVICEFACTORY->get<ISETSService> ()->Find (1, 1, setData), SG::DataStructure::Common::Status::STATUS_Success);

    ASSERT_EQ (setData.m_sId, 1);
    ASSERT_EQ (setData.m_setId, 1);
    ASSERT_EQ (setData.m_domainId, 1);
    ASSERT_EQ (setData.m_memeIds.size (), 724);  //

    ASSERT_EQ (DB_SERVICEFACTORY->get<ISETSService> ()->Find (1, 2, setData), SG::DataStructure::Common::Status::STATUS_Success);
    ASSERT_EQ (setData.m_memeIds.size (), 4200);

    ASSERT_EQ (DB_SERVICEFACTORY->get<ISETSService> ()->Find (1, 3, setData), SG::DataStructure::Common::Status::STATUS_Success);
    ASSERT_EQ (setData.m_memeIds.size (), 4229);

    ASSERT_EQ (DB_SERVICEFACTORY->get<ISETSService> ()->Find (1, 4, setData), SG::DataStructure::Common::Status::STATUS_Success);
    ASSERT_EQ (setData.m_memeIds.size (), 5);

    ASSERT_EQ (DB_SERVICEFACTORY->get<ISETSService> ()->Find (1, 5, setData), SG::DataStructure::Common::Status::STATUS_Success);
    ASSERT_EQ (setData.m_memeIds.size (), 5);

    ASSERT_EQ (DB_SERVICEFACTORY->get<ISETSService> ()->Find (1, 6, setData), SG::DataStructure::Common::Status::STATUS_Success);
    ASSERT_EQ (setData.m_memeIds.size (), 4);

    ASSERT_EQ (DB_SERVICEFACTORY->get<ISETSService> ()->Find (1, 7, setData), SG::DataStructure::Common::Status::STATUS_Success);
    ASSERT_EQ (setData.m_memeIds.size (), 10280);

    ASSERT_EQ (DB_SERVICEFACTORY->get<ISETSService> ()->Find (1, 8, setData), SG::DataStructure::Common::Status::STATUS_Success);
    ASSERT_EQ (setData.m_memeIds.size (), 2);
}

#include "DBManager/IService/Input/Parameter/IParameterService.h"
TEST_F (NastranParseBDFTest, PARAM_AUTOSPC_V1_BUG)
{
    auto _imp     = std::make_shared<BDFImporter> (DB_SERVICEFACTORY);
    auto filePath = SG::Utility::FileSystem::getTestDataPath ("Import/BDF/wentaiheat.bdf");
    _imp->Load (filePath.c_str ());

    auto param = DB_SERVICEFACTORY->get<IParameterService> ()->GetSolverParameter ();

    ASSERT_EQ (param["AUTOSPC"].GetString (), std::string ("YES"));
    ASSERT_EQ (param["SIGMA"].GetString (), std::string ("1.714-9"));
}

#include "DBManager/IService/Input/Dynamic/IEIGRService.h"
TEST_F (NastranParseBDFTest, EIGR_MISS)
{
    auto _imp     = std::make_shared<BDFImporter> (DB_SERVICEFACTORY);
    auto filePath = SG::Utility::FileSystem::getTestDataPath ("Import/BDF/INV.bdf");
    _imp->Load (filePath.c_str ());

    auto service = DB_SERVICEFACTORY->get<IEIGRService> ();

    ASSERT_EQ (service->Size (), 1);
}

TEST_F (NastranParseBDFTest, INCLUDE1)
{
    auto _imp     = std::make_shared<BDFImporter> (DB_SERVICEFACTORY);
    auto filePath = SG::Utility::FileSystem::getTestDataPath (
        "Import/BDF/EleTes-LinStatic-Include-FileNamesAnywhereMultipleLines/EleTes-LinStatic-Include-FileNamesAnywhereMultipleLines.bdf");
    ASSERT_EQ (Common::Status::STATUS_Success, _imp->Load (filePath.c_str ()));
}
TEST_F (NastranParseBDFTest, INCLUDE2)
{
    auto _imp     = std::make_shared<BDFImporter> (DB_SERVICEFACTORY);
    auto filePath = SG::Utility::FileSystem::getTestDataPath (
        "Import/BDF/EleTes-LinStatic-Include-LevelUpOtherFolder/Main/EleTes-LinStatic-Include-LevelUpOtherFolder.dat");
    ASSERT_EQ (Common::Status::STATUS_Success, _imp->Load (filePath.c_str ()));
}
TEST_F (NastranParseBDFTest, INCLUDE3PARENT)
{
    auto _imp     = std::make_shared<BDFImporter> (DB_SERVICEFACTORY);
    auto filePath = SG::Utility::FileSystem::getTestDataPath ("Import/BDF/include3parent/Main/main.bdf");
    ASSERT_EQ (Common::Status::STATUS_Success, _imp->Load (filePath.c_str ()));
}

TEST_F (NastranParseBDFTest, SOL105)
{
    auto _imp     = std::make_shared<BDFImporter> (DB_SERVICEFACTORY);
    auto filePath = SG::Utility::FileSystem::getTestDataPath ("Import/BDF/7out_SOL105.bdf");
    _imp->Load (filePath.c_str ());

    auto subcaseService = DB_SERVICEFACTORY->get<ISubcaseService> ();

    ASSERT_EQ (subcaseService->GetAllSubcaseID ().size (), 2);

    auto subcaseparam1 = subcaseService->FindSubCase (1);
    auto subcaseparam2 = subcaseService->FindSubCase (2);

    SG::DataStructure::FEM::Subcase subcase1 (subcaseparam1);
    SG::DataStructure::FEM::Subcase subcase2 (subcaseparam2);

    ASSERT_EQ (subcase1.GetSOLType (), SG::DataStructure::FEM::SOLType::SOL_SESTATIC);
    ASSERT_EQ (subcase2.GetSOLType (), SG::DataStructure::FEM::SOLType::SOL_SEBUCKL);
}

// #include "Utility/Logging/SGLogger.h"
// #include "DataStructure/Input/Element/CQUAD4Data.h"
// #include "DataStructure/Input/Element/CWELDData.h"
// #include "DBManager/IService/Input/Element/IElementService.h"
// TEST_F (NastranParseBDFTest, MALL_CWELD_CHECK)
// {
//     auto _imp     = std::make_shared<BDFImporter> (DB_SERVICEFACTORY);
//     auto filePath = "/root/SGSim/workspace/YUANTONG_670w_Cweld_SOL101_gai.bdf";
//     _imp->Load (filePath);

//     auto                                       service = DB_SERVICEFACTORY->get<IElementService> ();
//     std::vector<SG::DataStructure::Common::Id> allId   = service->GetAllId<FEM::CQUAD4Data> ();

//     // 转换为unordered_set方便后续查询
//     std::unordered_set<SG::DataStructure::Common::Id> allIdSet (allId.begin (), allId.end ());

//     SGInfo << "CQUAD4 Count allId:" << allId.size ();
//     SGInfo << "CQUAD4 Count allIdSet:" << allIdSet.size ();

//     FEM::CQUAD4Data fdata;

//     std::vector<FEM::CWELDData> allcweld = service->GetAllData<FEM::CWELDData> ();

//     SGInfo << "CWELD Count:" << allcweld.size ();
//     int count = 0;
//     for (auto&& i : allcweld)
//     {
//         count++;
//         if (count % 10000 == 0)
//         {
//             SGInfo << "Processed CWELD Count #@@:" << count;
//         }
//         if (i.m_format == 2)
//         {
//             if (service->FindElementNodes (i.m_ShIdA).size () != 4)
//             {
//                 SGWarn << i.m_id << " Cannot find element nodes id:" << i.m_ShIdA;
//             }
//             if (service->FindElementNodes (i.m_ShIdB).size () != 4)
//             {
//                 SGWarn << i.m_id << " Cannot find element nodes id:" << i.m_ShIdB;
//             }
//         }
//         else
//         {
//             SGWarn << i.m_id << " CWELD format is not GRIDID, but GA is given. CWELD ID: " << i.m_id;
//         }
//     }
// }